package btstack

/*
#include "ble/att_db_util.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"

type AttPropertyFlags uint16

const (
	AttPropertyBroadcast                AttPropertyFlags = 0x01
	AttPropertyRead                                      = 0x02
	AttPropertyWriteWithoutResponse                      = 0x04
	AttPropertyWrite                                     = 0x08
	AttPropertyNotify                                    = 0x10
	AttPropertyIndicate                                  = 0x20
	AttPropertyAuthenticatedSignedWrite                  = 0x40
	AttPropertyExtendedProperties                        = 0x80
)

type AttSecurityLevel uint8

const (
	AttSecurityNone AttSecurityLevel = iota
	AttSecurityEncrypted
	AttSecurityAuthenticated
	AttSecurityAuthorized
	AttSecurityAuthenticatedSc
)

func AttDbUtilInit() {
	C.att_db_util_init()
}

func AttDbUtilAddServiceUuid16(uuid16 uint16) uint16 {
	return uint16(C.att_db_util_add_service_uuid16(C.uint16_t(uuid16)))
}

func AttDbUtilAddServiceUuid128(uuid128 string) uint16 {
	cuuid128 := unsafe.Pointer(C.CString(uuid128))
	defer C.free(cuuid128)

	handle := uint16(C.att_db_util_add_service_uuid128((*C.uchar)(cuuid128)))

	return handle
}

func AttDbUtilAddSecondaryServiceUuid16(uuid16 uint16) uint16 {
	return uint16(C.att_db_util_add_secondary_service_uuid16(C.uint16_t(uuid16)))
}

func AttDbUtilAddSecondaryServiceUuid128(uuid128 string) uint16 {
	cuuid128 := unsafe.Pointer(C.CString(uuid128))
	defer C.free(cuuid128)

	handle := uint16(C.att_db_util_add_secondary_service_uuid128((*C.uchar)(cuuid128)))

	return handle
}

func AttDbUtilAddCharacteristicUuid16(uuid16 uint16, properties AttPropertyFlags, readPermission, writePermission AttSecurityLevel, data []byte) uint16 {
	cData := C.CBytes(data)
	defer C.free(unsafe.Pointer(cData))

	handle := uint16(C.att_db_util_add_characteristic_uuid16(C.ushort(uuid16), C.ushort(properties),
		C.uint8_t(readPermission), C.uint8_t(writePermission), (*C.uint8_t)(cData), (C.ushort)(len(data))))

	return handle
}

func AttDbUtilAddCharacteristicUuid128(uuid128 string, properties AttPropertyFlags, readPermission, writePermission AttSecurityLevel, data []byte) uint16 {
	cuuid128 := unsafe.Pointer(C.CString(uuid128))
	cData := C.CBytes(data)

	defer func() {
		C.free(cuuid128)
		C.free(unsafe.Pointer(cData))
	}()

	handle := uint16(C.att_db_util_add_characteristic_uuid128((*C.uchar)(cuuid128), C.ushort(properties),
		C.uint8_t(readPermission), C.uint8_t(writePermission), (*C.uint8_t)(cData), (C.ushort)(len(data))))

	return handle
}

func AttDbUtilAddDescriptorUuid16(uuid16 uint16, properties AttPropertyFlags, readPermission, writePermission AttSecurityLevel, data []byte) uint16 {
	cData := C.CBytes(data)
	defer C.free(unsafe.Pointer(cData))

	handle := uint16(C.att_db_util_add_descriptor_uuid16(C.ushort(uuid16), C.ushort(properties),
		C.uint8_t(readPermission), C.uint8_t(writePermission), (*C.uint8_t)(cData), (C.ushort)(len(data))))

	return handle
}

func AttDbUtilAddDescriptorUuid128(uuid128 string, properties AttPropertyFlags, readPermission, writePermission AttSecurityLevel, data []byte) uint16 {
	cuuid128 := unsafe.Pointer(C.CString(uuid128))
	cData := C.CBytes(data)

	defer func() {
		C.free(cuuid128)
		C.free(unsafe.Pointer(cData))
	}()

	handle := uint16(C.att_db_util_add_descriptor_uuid128((*C.uchar)(cuuid128), C.ushort(properties),
		C.uint8_t(readPermission), C.uint8_t(writePermission), (*C.uint8_t)(cData), (C.ushort)(len(data))))

	return handle
}

func AttDbUtilGetAddress() []byte {
	db := C.att_db_util_get_address()
	size := C.att_db_util_get_size()
	return C.GoBytes(unsafe.Pointer(db), C.int(size))
}

func AttDbUtilHashLen() uint16 {
	return uint16(C.att_db_util_hash_len())
}

func AttDbUtilHashInit() {
	C.att_db_util_hash_init()
}

func AttDbUtilHashGetNext() byte {
	return byte(C.att_db_util_hash_get_next())
}
